import constants from '@/constants';
import { InjectRedis } from '@/decorators';
import { getNanoid, halt } from '@/utils';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import { createHash } from 'crypto';
import { Redis } from 'ioredis';

@Injectable()
export class ShuwenService {
  @InjectRedis()
  private readonly redis: Redis;
  private readonly apiUrl: string;
  private readonly appId: string;
  private readonly appSecret: string;
  private readonly contract: string;
  constructor(private readonly config: ConfigService) {
    this.apiUrl = this.config.get('chain.apiUrl');
    this.appId = this.config.get('chain.appId');
    this.appSecret = this.config.get('chain.appSecret');
    this.contract = this.config.get('chain.contract');
  }

  public async createHash() {
    const id = await getNanoid(32);
    return new Promise((r) =>
      r('0x' + createHash('sha256').update(id).digest('hex')),
    );
  }

  public async createAccount(id?: string) {
    const res = await this.post(
      `/component/management-platform/api/v1/application/identity/create`,
      {
        appUserCode: id,
      },
    );
    if (res.code !== 200) {
      return halt(`创建链账户失败: ${res?.message ?? '未知错误'}`);
    }
    return res.data;
    // id = id ?? (await getNanoid(32));
    // return new Promise((r) => r(createHash('sha256').update(id).digest('hex')));
  }

  public async mint(nft: any): Promise<string> {
    const id = await getNanoid(32);
    return new Promise((r) =>
      r(
        createHash('sha256')
          .update(
            JSON.stringify({
              ...nft,
              id,
              createTime: Date.now(),
            }),
          )
          .digest('hex'),
      ),
    );
  }

  public async classesDeploy(data: any = {}, headers: any = {}) {
    return await this.post(
      `/component/nft-service-chain-${this.contract}/api/v1/classes/deploy`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async classesDetail(data: any = {}, headers: any = {}) {
    return await this.get(
      `/component/nft-service-chain-${this.contract}/api/v1/classes/detail`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async nftMint(data: any = {}, headers: any = {}) {
    return await this.post(
      `/component/nft-service-chain-${this.contract}/api/v1/nft/mint`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async nftBurn(data: any = {}, headers: any = {}) {
    return await this.post(
      `/component/nft-service-chain-${this.contract}/api/v1/nft/burn`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async nftDetail(data: any = {}, headers: any = {}) {
    return await this.get(
      `/component/nft-service-chain-${this.contract}/api/v1/nft/detail`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async nftTransfer(data: any = {}, headers: any = {}) {
    return await this.post(
      `/component/nft-service-chain-${this.contract}/api/v1/nft/transfer`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async nftTx(data: any = {}, headers: any = {}) {
    return await this.get(
      `/component/nft-service-chain-${this.contract}/api/v1/nft/tx`,
      data,
      {
        'app-user-code': constants.default.mobile,
        ...headers,
      },
    );
  }

  public async get(url: string, params: any = {}, headers: any = {}) {
    return await axios
      .get(`${this.apiUrl}${url}`, {
        params,
        headers: {
          ...(await this.getHeaders()),
          ...headers,
        },
      })
      .then((res) => res.data);
  }

  public async post(url: string, data: any = {}, headers: any = {}) {
    return await axios
      .post(`${this.apiUrl}${url}`, data, {
        headers: {
          ...(await this.getHeaders()),
          ...headers,
        },
      })
      .then((res) => res.data);
  }

  public async generateOperationId() {
    return await getNanoid(32);
  }

  private async getAccessToken() {
    return await axios
      .post(`${this.apiUrl}/billing-charge-service/blockServer/getToken`, {
        appId: this.appId,
        appSecret: this.appSecret,
      })
      .then((res) => res.data);
  }

  private async getHeaders() {
    let token = await this.redis.get(`blockchain:token`);
    if (!token) {
      const data = await this.getAccessToken();
      if (data.code !== 0) {
        return halt(`获取AccessToken失败: ${data?.message ?? '未知错误'}`);
      }
      token = data.result.token;
      await this.redis.set(
        `blockchain:token`,
        token,
        'EX',
        Number(data.result.expireTime) - 20,
      );
    }
    return {
      'Content-Type': 'application/json',
      'x-authorization': token,
    };
  }
}
